using System.Diagnostics;
using System.IO.Compression;
using System.Net.Http.Headers;
using System.Net;
using System.Text;
using System.Xml.Linq;
using MultiAgentsServer.Scripts.Shared;
using Debug = MultiAgentsShared.Debug;

namespace MultiAgentsClient.Manager;

public class AutoUpdateOperator
{
    private readonly string BaseUrl = "http://101.132.38.124:8111";
    private readonly string username = "OctoTaskApi";
    private readonly string password = "Dd1243568790";
#if LOCALDEV
    private readonly string buildType = "MultiAgentsClient_Develop";
#elif DEVELOP
    private readonly string buildType = "MultiAgentsClient_Develop";
#elif RELEASE
    private readonly string buildType = "MultiAgentsClient_Release";
#endif
    private string lastBuildId = "";
    private string artifactName = "";
    private readonly string downloadDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), FileConsts.UpdateTemplateDirectoryName);

    public async Task<bool> CheckHasNewVersion()
    {
        string url = BaseUrl + $"/httpAuth/app/rest/builds/?locator=status:SUCCESS,buildType:{buildType},count:1";
        HttpResult httpResult = await HttpToolProvider.SendBasicAuthHttpRequestAsync("GET", url, username, password, "STRING", "");
        string xmlContent = httpResult.Content;

        XDocument doc = XDocument.Parse(xmlContent);
        XElement? buildElement = doc.Root?.Element("build");
        string versionNumber = buildElement?.Attribute("number")?.Value ?? throw Debug.ShouldNotHappen();
        lastBuildId = buildElement?.Attribute("id")?.Value ?? throw Debug.ShouldNotHappen();

        string localVersionNumber = FileOperationToolProvider.LoadFile(FileConsts.VersionNumberFileName).Trim();
        return localVersionNumber != versionNumber;
    }

    private async Task DownloadBuildArtifact()
    {
        string artifactsUrl = BaseUrl + $"/app/rest/builds/id:{lastBuildId}/artifacts/";
        HttpResult httpResult = await HttpToolProvider.SendBasicAuthHttpRequestAsync("GET", artifactsUrl, username, password, "STRING", "");
        string artifactsXml = httpResult.Content;

        XDocument artifactDoc = XDocument.Parse(artifactsXml);
        XElement? artifactElement = artifactDoc.Root?.Element("file");
        artifactName = artifactElement?.Attribute("name")?.Value ?? throw Debug.ShouldNotHappen();


        string artifactDownloadUrl = BaseUrl + $"/httpAuth/app/rest/builds/id:{lastBuildId}/artifacts/content/{artifactName}";
        ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;

        HttpClientHandler handler = new()
        {
            ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true
        };
        HttpClient client = new(handler);

        var byteArray = new UTF8Encoding().GetBytes($"{username}:{password}");
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

        HttpResponseMessage response = await client.GetAsync(artifactDownloadUrl);
        response.EnsureSuccessStatusCode();

        byte[] fileBytes = await response.Content.ReadAsByteArrayAsync();

        string downloadPath = Path.Combine(downloadDirectory, artifactName);

        

        string tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(downloadPath));
        await File.WriteAllBytesAsync(tempFilePath, fileBytes);

        string command = $"(IF EXIST \"{downloadDirectory}\" (rmdir /S /Q \"{downloadDirectory}\" & MKDIR \"{downloadDirectory}\") ELSE (MKDIR \"{downloadDirectory}\")) & MOVE /Y \"{tempFilePath}\" \"{downloadPath}\"";

        CmdResult result = CmdToolProvider.ExecuteCommand(command, "", true);

        if (result.ExitCode != 0)
        {
            throw new InvalidOperationException($"Failed to prepare directory and move file: {result.Error}");
        }
    }

    public void ExtractAndDeleteZip(string artifactName)
    {
        try
        {
            string zipFilePath = Path.Combine(downloadDirectory, artifactName);

            ZipFile.ExtractToDirectory(zipFilePath, downloadDirectory);

            File.Delete(zipFilePath);
        }
        catch (IOException ioEx)
        {
            Debug.Log($"An I/O error occurred: {ioEx.Message}");
        }
        catch (UnauthorizedAccessException uaEx)
        {
            Debug.Log($"Access error (insufficient permissions): {uaEx.Message}");
        }
        catch (Exception ex)
        {
            Debug.Log($"An error occurred: {ex.Message}");
        }
    }

    public void StartUpdateScript()
    {
        string batFilePath = @".\updater.bat";

        ProcessStartInfo processStartInfo = new()
        {
            FileName = batFilePath,
            UseShellExecute = false,
            RedirectStandardOutput = false,
            RedirectStandardError = false,
            CreateNoWindow = true
        };

        Process.Start(processStartInfo);
    }

    public async Task UpdateProject()
    {
        await DownloadBuildArtifact();

        ExtractAndDeleteZip(artifactName);

        StartUpdateScript();

        Environment.Exit(0);
    }

    public async Task KeepCheckNewVersion()
    {
        string url = BaseUrl + $"/httpAuth/app/rest/builds/?locator=status:SUCCESS,buildType:{buildType},count:1";
        string localVersionNumber = FileOperationToolProvider.LoadFile(FileConsts.VersionNumberFileName).Trim();

        while (true)
        {
            await Task.Delay(5000);
            
            HttpResult httpResult = await HttpToolProvider.SendBasicAuthHttpRequestAsync("GET", url, username, password, "STRING", "");
            string xmlContent = httpResult.Content;

            XDocument doc = XDocument.Parse(xmlContent);
            XElement? buildElement = doc.Root?.Element("build");
            string versionNumber = buildElement?.Attribute("number")?.Value ?? throw Debug.ShouldNotHappen();
            lastBuildId = buildElement?.Attribute("id")?.Value ?? throw Debug.ShouldNotHappen();

            if (localVersionNumber != versionNumber)
            {
                Debug.LogWindow("发现新版本，请重启应用更新客户端。");
                return;
            }
        }
    }
}
